use tao::{
    event::{Event, StartCause, WindowEvent},
    event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
    window::WindowBuilder,
};
use wry::{http, WebView, WebViewBuilder};

#[cfg(target_os = "android")]
fn init_logging() {
    android_logger::init_once(
        android_logger::Config::default()
            .with_max_level(log::LevelFilter::Trace)
            .with_tag("{{app.name}}"),
    );
}

#[cfg(not(target_os = "android"))]
fn init_logging() {
    env_logger::init();
}

#[cfg(any(target_os = "android", target_os = "ios"))]
fn stop_unwind<F: FnOnce() -> T, T>(f: F) -> T {
    match std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) {
        Ok(t) => t,
        Err(err) => {
            eprintln!("attempt to unwind out of `rust` with err: {:?}", err);
            std::process::abort()
        }
    }
}

#[cfg(any(target_os = "android", target_os = "ios"))]
fn _start_app() {
    stop_unwind(|| main());
}

#[no_mangle]
#[inline(never)]
#[cfg(any(target_os = "android", target_os = "ios"))]
pub extern "C" fn start_app() {
    #[cfg(target_os = "android")]
    {
        tao::android_binding!(
            {{snake-case (ident-no-last-part app.identifier)}},
            {{snake-case (ident-last-part app.name)}},
            WryActivity,
            wry::android_setup, // pass the wry::android_setup function to tao which will invoke when the event loop is created
            _start_app
        );
        wry::android_binding!({{snake-case (ident-no-last-part app.identifier)}}, {{snake-case (ident-last-part app.name)}});
    }

    #[cfg(target_os = "ios")]
    _start_app()
}

pub fn main() {
    init_logging();
    let event_loop = EventLoop::new();

    let mut webview = None;
    event_loop.run(move |event, event_loop, control_flow| {
        *control_flow = ControlFlow::Wait;

        match event {
            Event::NewEvents(StartCause::Init) => {
                webview = Some(build_webview(event_loop).unwrap());
            }
            Event::WindowEvent {
                event: WindowEvent::CloseRequested { .. },
                ..
            } => {
                webview.take();
                *control_flow = ControlFlow::Exit;
            }
            _ => (),
        }
    });
}

fn build_webview(event_loop: &EventLoopWindowTarget<()>) -> anyhow::Result<WebView> {
    let window = WindowBuilder::new()
        .with_title("A fantastic window!")
        .build(&event_loop)?;
    
    let builder = WebViewBuilder::new()
        .with_url("https://tauri.app")
        // If you want to use custom protocol, set url like this and add files like index.html to assets directory.
        // .with_url("wry://assets/index.html")?
        .with_devtools(true)
        .with_initialization_script("console.log('hello world from init script');")
        .with_ipc_handler(|s| {
            dbg!(s);
        })
        .with_custom_protocol("wry".into(), move |_, _request| {
            http::Response::builder()
                .header(http::header::CONTENT_TYPE, "text/html")
                .body(
                    r#"<html>
                <body>
                  Hello Wry!!
                </body>
                </html>"#
                        .as_bytes()
                        .into(),
                )
                .unwrap_or_default()
        });

    #[cfg(any(
        target_os = "windows",
        target_os = "macos",
        target_os = "ios",
        target_os = "android"
    ))]
    let webview = builder.build(&window)?;
    #[cfg(not(any(
        target_os = "windows",
        target_os = "macos",
        target_os = "ios",
        target_os = "android"
    )))]
    let webview = {
        use tao::platform::unix::WindowExtUnix;
        use wry::WebViewBuilderExtUnix;
        let vbox = window.default_vbox().unwrap();
        builder.build_gtk(vbox)?
    };

    Ok(webview)
}